Skip to content

refactor(ui): ProductList i18n data + link-card redesign#18815

Open
myelinated-wackerow wants to merge 11 commits into
devfrom
product-list
Open

refactor(ui): ProductList i18n data + link-card redesign#18815
myelinated-wackerow wants to merge 11 commits into
devfrom
product-list

Conversation

@myelinated-wackerow

@myelinated-wackerow myelinated-wackerow commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

Rebuilds ProductList and migrates its four consumers.

  • Component — simplified the API (required, self-descriptive ctaLabel; parentHeadingLevel; pure presentational), then rebuilt items as ghost link cards: the whole card is the link (href on Card + CardButtonFake as the sole action, no nested links), a logo thumbnail beside title/description, and a CTA that goes full-width on narrow cards and fit-content once the card is wide (@container/card).
  • Content / i18n — moved hardcoded product titles/descriptions/CTAs into intl namespaces (new component-prediction-market-products.json, component-restaking-products.json); CTAs use a shared "Visit {brand}" skeleton fed a translated brand key rather than a hardcoded literal; stablecoins tool titles are now keyed (Dune/Visa keep a long title key separate from the short CTA brand); dropped an inline link from the Luna copy (invalid inside a card-link).
  • Gridcolumns={1} support.
  • Docs — design-system skill: the interpolate-a-translated-value i18n rule; ProductList documented as a card grid.

Test plan

  • /stablecoins tools list, AI-agents lists, prediction-markets, restaking: cards render, whole card links, single CTA works.
  • Light + dark (ghost hover fill; Dune logo dark-invert).
  • Responsive: 1-col (wide -> fit CTA), 2-col (stablecoins), narrow/mobile (full-width CTA).
  • RTL (ar): logo/text/CTA layout mirrors.

myelinated-wackerow and others added 11 commits July 3, 2026 15:41
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Require a complete, self-descriptive ctaLabel per item and drop the shared actionLabel fallback and its synthesized aria-label, so the component is pure presentational -- no getTranslations, no async.

Headings derive from a parentHeadingLevel prop, and the CTA now stacks below the content at every width instead of sitting inline on wide rows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Move hardcoded product titles, descriptions, and CTAs into their intl namespaces and render the lists from async Server Components via getTranslations.

CTAs use a shared "Visit {brand}" skeleton that interpolates a translated brand key, rather than repeating the prefix across labels or injecting hardcoded English literals.

Stablecoins tool titles become keys too; Dune and Visa keep a long title key separate from the short CTA brand key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Document the Grid-as-semantic-list pattern (asChild ul, list-none plus role=list, fold-independent dividers) and the bare ul/li legacy-style gotcha.

Clarify the translation boundary -- getTranslations for Server Components, the custom useTranslation hook for genuine client components, never next-intl useTranslations directly -- and the rule to interpolate a translated value rather than a hardcoded literal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
# Conflicts:
#	.claude/skills/design-system/references/i18n-rtl.md
#	.claude/skills/design-system/references/server-vs-client.md
Render each item as a ghost Card whose whole surface links to the product: href on the Card with a CardButtonFake as the sole action, so there are no nested links in the copy.

Layout is a row -- a fixed-width logo thumbnail beside a content column. The CTA sits at the bottom of the column, full-width on narrow cards and fit-content once the card is wide enough (@container/card). Drops the old semantic-list + fold-independent-divider structure for the plain card-grid convention.

Story updated to the current API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
The whole ProductList card is now a single link, so a nested anchor in the copy is invalid HTML. Flatten Luna's TikTok link in its description to plain (bold) text.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
ProductList no longer uses the Grid-as-semantic-list + fold-independent-divider pattern, so remove that section from components.md and the now-dangling cross-reference from the bare-ul/li gotcha.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
asChild was added to support a Grid-as-<ul> semantic-list pattern that ProductList no longer uses, and nothing else consumes it. Remove the prop, its Slot import, and the doc bullet; the cols=1 support from the same original change stays.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
@netlify

netlify Bot commented Jul 15, 2026

Copy link
Copy Markdown

Deploy Preview for ethereumorg ready!

Name Link
🔨 Latest commit 3fe1c29
🔍 Latest deploy log https://app.netlify.com/projects/ethereumorg/deploys/6a581b801e115e0008fe95b8
😎 Deploy Preview https://deploy-preview-18815.ethereum.it
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
7 paths audited
Performance: 58 (🟢 up 2 from production)
Accessibility: 95 (no change from production)
Best Practices: 100 (no change from production)
SEO: 98 (no change from production)
PWA: 59 (🔴 down 1 from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added content 🖋️ This involves copy additions or edits translation 🌍 This is related to our Translation Program labels Jul 15, 2026
@github-actions

This comment has been minimized.

@wackerow
wackerow marked this pull request as draft July 16, 2026 14:41
@wackerow wackerow added the needs design approval 🧑‍🎨 Approval from a designer is needed before merging label Jul 16, 2026
@wackerow
wackerow marked this pull request as ready for review July 16, 2026 17:32
@github-actions

Copy link
Copy Markdown
Contributor

🔎 First-pass review — ✅ Looks mergeable

Clean team refactor of ProductList and its four consumers: items become ghost link-cards (whole Card is the anchor, CardButtonFake as sole action — the correct no-nested-interactive pattern), hardcoded titles/descriptions/CTAs move into intl namespaces, and the CTA adopts the interpolate-a-translated-brand skeleton. Conventions hold and no checks are failing — Netlify preview and Storybook are green; Chromatic UI Tests are still running.

Verified during review

  • grid-cols-auto-1 resolves — grid-cols-auto-* is a wildcard @utility in utilities.css, so the new columns:1 variant generates.
  • The three consumers converted from useTranslationsasync + getTranslations are only rendered through the MDX registry (MdComponents), which is RSC — no "use client" boundary, so the async server-component conversion is safe (same pattern as the stablecoins/dev-tools pages).
  • i18n follows the interpolate-a-translated-value rule (t("visit-brand", { brand: t("...-brand") })) with brands keyed; no raw Intl.*; removed ButtonLink/InlineLink imports cleaned up in all consumers.
  • Removed inline <a> from the Luna copy (invalid inside a card-link) — English-source edit, correctly left for the intl pipeline rather than hand-propagated.

Human steps (non-blocking)

  • Chromatic will surface diffs for every ProductList surface (stablecoins tools, AI-agents, prediction-markets, restaking) — a designer needs to accept the new card layout (design-approval label already applied).
Analysis

Lane: code (dominant substance in src/components/** + app/**; also English intl and design-system docs).

Checked: component API change (linkhref, required ctaLabel, description now ReactNode | ReactNode[], parentHeadingLevel heading hierarchy), Card/Grid usage against the actual component contracts, translatability of all user-facing strings, unused-import/var hygiene, and CI status. No convention violations found. columns prop narrowed to 2 externally (single-column is the default via columns || 1 internally) — all callers updated. Heading hierarchy is parametrized sensibly (h3 category / h4 product under a page h2).

Nothing blocking. The Grid arrow-body was rewrapped in { return (...) } with no behavior change — cosmetic only.

Generated by PR Reviewer (team) for #18815 · 106.4 AIC · ⌖ 27.6 AIC · ⊞ 5.2K ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

content 🖋️ This involves copy additions or edits needs design approval 🧑‍🎨 Approval from a designer is needed before merging translation 🌍 This is related to our Translation Program

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants